package service

import (
	"context"
	"errors"
	"fmt"
	"mall_2.0/config"
	"mall_2.0/consts"
	"mall_2.0/pkg/utils/ctl"
	"mall_2.0/pkg/utils/email"
	"mall_2.0/pkg/utils/jwt"
	"mall_2.0/pkg/utils/log"
	utils "mall_2.0/pkg/utils/upload"
	"mall_2.0/respository/db/dao"
	"mall_2.0/respository/db/model"
	"mall_2.0/types"
	"mime/multipart"
	"sync"
)

var UserSrvIns *UserSrv
var UserSrvOnce sync.Once

type UserSrv struct{}

func GetUserSrv() *UserSrv {
	UserSrvOnce.Do(func() {
		UserSrvIns = &UserSrv{}
	})
	return UserSrvIns
}

// RegisterUser 用户注册
func (us *UserSrv) RegisterUser(ctx context.Context, req *types.UserRegisterReq) (resp interface{}, err error) {
	userDao := dao.NewUserDao(ctx)
	_, exist, err := userDao.ExistOrNotByUserName(req.UserName)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	if exist {
		err = errors.New("用户已存在")
		return
	}
	user := &model.User{
		NickName: req.UserName,
		UserName: req.UserName,
		Status:   model.Active,
		Money:    consts.UserInitMoney,
	}
	// 加密密码
	if err = user.SetPassword(req.Password); err != nil {
		log.LogrusObj.Error(err)
		return
	}
	// 加密余额
	money, err := user.EncryptMoney(req.Key)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	user.Money = money
	// 默认头像
	user.Avatar = consts.UserDefaultAvatarLocal
	if config.Config.System.UploadModel == consts.UploadModelOss {
		user.Avatar = consts.UserDefaultAvatarOss
	}

	// 创建用户
	err = userDao.CreateUser(user)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	return
}

// LoginUser 用户登录
func (us *UserSrv) LoginUser(ctx context.Context, req *types.UserLoginReq) (resp interface{}, err error) {
	userDao := dao.NewUserDao(ctx)
	user, exist, err := userDao.ExistOrNotByUserName(req.UserName)
	if !exist {
		log.LogrusObj.Error(err)
		return nil, errors.New("用户不存在")
	}
	if !user.CheckPassword(req.Password) {
		return nil, errors.New("账号/密码不正确")
	}
	accessToken, refreshToken, err := jwt.GenerateToken(user.ID, req.UserName)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	userResp := &types.UserInfoResp{
		ID:       user.ID,
		UserName: user.UserName,
		NickName: user.NickName,
		Email:    user.Email,
		Status:   user.Status,
		Avatar:   user.Avatar,
		CreateAt: user.CreatedAt.Unix(),
	}
	resp = &types.UserTokenData{
		User:         userResp,
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
	}
	return
}

// UpdateUserInfo 修改用户信息
func (us *UserSrv) UpdateUserInfo(ctx context.Context, req *types.UserInfoUpdateReq) (resp interface{}, err error) {
	userDao := dao.NewUserDao(ctx)
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	user, err := userDao.GetUserById(u.ID)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	if req.NickName != "" {
		user.NickName = req.NickName
	}
	err = userDao.UpdateUserById(u.ID, user)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	return
}

// ShowUserInfo 获取用户信息
func (us *UserSrv) ShowUserInfo(ctx context.Context, req *types.UserInfoShowReq) (resp interface{}, err error) {
	userDao := dao.NewUserDao(ctx)
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	user, err := userDao.GetUserById(u.ID)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}
	resp = &types.UserInfoResp{
		ID:       user.ID,
		UserName: user.UserName,
		NickName: user.NickName,
		Email:    user.Email,
		Avatar:   user.Avatar,
		Status:   user.Status,
		CreateAt: user.CreatedAt.Unix(),
	}
	return
}

// SendEmail 发送邮件
func (us *UserSrv) SendEmail(ctx context.Context, req *types.SendEmailServiceReq) (resp interface{}, err error) {
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	var address string
	token, err := jwt.GenerateEmailToken(u.ID, req.OperationType, req.Email, req.Password)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	sender := email.NewEmailSender()
	address = config.Config.Email.Address + token
	mailText := fmt.Sprintf(consts.EmailOperationMap[int(req.OperationType)], address)
	if err = sender.SendMail(mailText, req.Email, "clockleaf"); err != nil {
		log.LogrusObj.Error(err)
		return
	}
	return
}

// Valid 验证邮件
func (us *UserSrv) Valid(ctx context.Context, req *types.ValidEmailServiceReq) (resp interface{}, err error) {
	var uID uint
	var uEmail string
	var password string
	var operationType uint

	// 验证Token
	if req.Token == "" {
		err = errors.New("token不存在")
		log.LogrusObj.Error(err)
		return
	}
	claims, err := jwt.ParseEmailToken(req.Token)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	} else {
		uID = claims.UserID
		uEmail = claims.Email
		password = claims.Password
		operationType = claims.OperationType
	}

	// 获取用户信息
	userDao := dao.NewUserDao(ctx)
	u, err := userDao.GetUserById(uID)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}

	switch operationType {
	case consts.EmailOperationBinding:
		u.Email = uEmail
	case consts.EmailOperationNoBinding:
		u.Email = ""
	case consts.EmailOperationUpdatePassword:
		err = u.SetPassword(password)
		if err != nil {
			err = errors.New("密码加密错误")
			return
		}
	default:
		return nil, errors.New("操作不符合")
	}

	err = userDao.UpdateUserById(u.ID, u)
	if err != nil {
		log.LogrusObj.Error(err)
		return
	}

	resp = &types.UserInfoResp{
		ID:       u.ID,
		UserName: u.UserName,
		NickName: u.NickName,
		Email:    u.Email,
		Avatar:   u.Avatar,
		Status:   u.Status,
		CreateAt: u.CreatedAt.Unix(),
	}
	return
}

// UserFollow 关注用户
func (us *UserSrv) UserFollow(ctx context.Context, req *types.UserFollowingReq) (resp interface{}, err error) {
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	userDao := dao.NewUserDao(ctx)
	err = userDao.FollowUser(u.ID, req.Id)
	return
}

// UserUnFollow 取关用户
func (us *UserSrv) UserUnFollow(ctx context.Context, req *types.UserUnFollowingReq) (resp interface{}, err error) {
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	userDao := dao.NewUserDao(ctx)
	err = userDao.UnFollowUser(u.ID, req.Id)
	return
}

// UserAvatarUpload 更新头像
func (us *UserSrv) UserAvatarUpload(ctx context.Context, file multipart.File, fileSize int64, req *types.UserServiceReq) (resp interface{}, err error) {
	u, err := ctl.GetUserInfo(ctx)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	userDao := dao.NewUserDao(ctx)
	user, err := userDao.GetUserById(u.ID)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}

	var path string
	if config.Config.System.UploadModel == consts.UploadModelLocal {
		path, err = utils.AvatarUploadToLocalStatic(file, u.ID, user.UserName)
	} else {
		path, err = utils.UploadToQiNiu(file, fileSize)
	}
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}

	user.Avatar = path
	err = userDao.UpdateUserById(user.ID, user)
	if err != nil {
		log.LogrusObj.Error(err)
		return nil, err
	}
	return
}
